// ======================================================================
// FileName : param_counter_top.v:  
// Function : Top level of a design showing the use of verilog parameters 
//            to modify the width of data objects.
//
// The Counter module does a simple count; the Converter module
// copies the result into a register of configurable width.
//
// Notice that the `define is used only at the top level.
// This is just for demonstration purposes; a better
// idea would be to define a parameter pWidth in the top
// level module header.
//
// This module contains the top structure of the design, which
// is made up of two lower-level modules.
//
// ---------------------------------------------------------------------
// Author   : QilinZhao
// Version  : v-1.0
// Date     : 2013-06-28
// E-mail   : forqilin@163.com
// Copyright: QiXin Studio
// ====================================================================

`define PADWIDTH 3  // Global width; controls parameter values.
                    // No reference to PADWIDTH except at top.

module param_counter_top  // Top-level params in ANSI format:
      #(parameter WIDTH = `PADWIDTH,  // Saves repeated "-1".
                  PAD_NUM = 5         // The Count width control.
       )
       ( output[WIDTH-1+PAD_NUM:0] count,
         input  clk, count_enable, count_reset, out_enable);
  
  wire[WIDTH-1:0] Xfer;  // Local bus to connect module instances.
 
  // instance - hirarchy (XMR)
  // Pass parameter values by name (position):
  counter #(.WIDTH(WIDTH)) 
          u_counter( .count        (Xfer        ), 
                     .clk          (clk         ), 
                     .count_enable (count_enable), 
                     .count_reset  (count_reset )
                   );
  
  converter #(.WIDTH(WIDTH), .PAD_NUM(PAD_NUM))  
            u_converter01( .out_bus    (count), 
                           .in_bus     (Xfer), 
                           .enable     (out_enable)
                         );
  
endmodule // param_counter_top.

module tb; //testbench
  
  // The parameter definitions in TestBench are redundant,
  // because testbench will not be synthesized.
  // Changing testbench param values will override the
  // values in the design, which become defaults when
  // the design is instantiated in the testbench module:
  
  parameter WIDTH = `PADWIDTH , PAD_NUM = 3;
  
  wire[WIDTH-1+PAD_NUM:0] CountTest;
  reg count_enableTest
      , clockTest
      , CountResetTest
      , OutEnableTest;
  
  // Design instance:
  param_counter_top
      #(.WIDTH(WIDTH), .PAD_NUM(PAD_NUM)) // Pass testbench size to design.
    u_param_counter_top (
         .count         (CountTest        ),
         .count_enable  (count_enableTest ),
         .clk           (clockTest        ),
         .count_reset   (CountResetTest   ),
         .out_enable    (OutEnableTest    )
       );
  
  initial
    begin
    #01 clockTest        = 1'b0;
        count_enableTest = 1'b0;
        CountResetTest   = 1'b0;
        OutEnableTest    = 1'b0;
    #02 CountResetTest   = 1'b1;
    #02 CountResetTest   = 1'b0;
    
    #01 count_enableTest = 1'b1;
    #02 OutEnableTest    = 1'b1;
    // Later, we shall see better ways to
    // define a clock:
    #05 clockTest        = 1'b1;
    #05 clockTest        = 1'b0;
    #05 clockTest        = 1'b1;
    #05 clockTest        = 1'b0;
    #01 OutEnableTest    = 1'b0;
    #02 OutEnableTest    = 1'b1;
    #05 clockTest        = 1'b1;  // clock skips #3 here.
    #05 clockTest        = 1'b0;
    #05 clockTest        = 1'b1;
    #05 clockTest        = 1'b0;
    #05 clockTest        = 1'b1;
    #05 clockTest        = 1'b0;
    #05 clockTest        = 1'b1;
    #05 clockTest        = 1'b0;
    #05 clockTest        = 1'b1;
    #05 clockTest        = 1'b0;
    #05 clockTest        = 1'b1;
    #05 clockTest        = 1'b0;
    #05 clockTest        = 1'b1;
    #05 clockTest        = 1'b0;
    #05 clockTest        = 1'b1;
    #05 clockTest        = 1'b0;
    #05 clockTest        = 1'b1;
    #10 $finish;
    end
  initial begin
    $vcdpluson();
  end
endmodule // tb
